package bayesian;

import java.util.Random;

import probability.GaussianDistribution;
import probability.MultivariateGaussianDistribution;
import utils.Printer;
import basics.DenseMatrix;
import basics.DenseVector;
import basics.FeaturesSet;
import basics.Matrix;
import basics.Vector;
import basics.VectorMatrix;
import basics.VectorMatrixUtils.OperationOpt;

public class JointBayesian {

	GaussianDistribution _U;
	GaussianDistribution _V;

	public void train(FeaturesSet X, FeaturesSet Y, FeaturesSet R, int lDimension) {
		// _U = new MultivariateGaussianDistribution();
		// _V = new MultivariateGaussianDistribution();

		for (int i = 0; i < X.size(); i++) {
			for (int j = 0; j < Y.size(); j++) {
				if (R.get(i).get(j) != 0) {
					System.out.println(i + "," + j);
					update((Vector) X.get(i), (Vector) Y.get(j), R.get(i).get(j), lDimension);
					// Printer.appendToFile("uv.txt", "Iteration " + i + ", " + j + toString(_U)
					// + "\n-------------------------------------");
					// Printer.appendToFile("uv.txt", toString(_V) + "\n-------------------------------------");
				}
			}
		}

		_U = _V = null;

	}

	private void update(Vector x, Vector y, double r, int lDimension) {
		GaussianDistribution u = new GaussianDistribution(_U.getMu(), _U.getSigma2());
		GaussianDistribution v = new GaussianDistribution(_V.getMu(), _V.getSigma2());

		// for (int i = 0; i < x.length(); i++) {
		// for (int k = 0; k < lDimension; k++) {
		// Vector z = _VMean.timesCopy(y.transpose()).getColumnVector();
		// u[i][k] = newUV(i, k, _U[i][k], _U, x, z, k, r, usum); // new GaussianDistribution(1, 1)
		//
		// }
		// }
		// _U = u;
		//
		// for (int j = 0; j < y.length(); j++) {
		// for (int k = 0; k < lDimension; k++) {
		// Vector z = x.timesCopy(_UMean).getColumnVector();
		// v[k][j] = newUV(k, j, _V[k][j], _V, y, z, k, r, vsum); // new GaussianDistribution(1, 1)
		// }
		// }
		// _V = v;
	}

	private String toString(GaussianDistribution[][] p) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < p.length; i++) {
			for (int j = 0; j < p[0].length; j++) {
				sb.append(p[i][j].toString());
			}
		}
		return sb.toString();
	}

	private DenseMatrix getMeanMatrix(GaussianDistribution[][] p) {
		DenseMatrix m = new DenseMatrix(p.length, p[0].length);

		for (int i = 0; i < p.length; i++) {
			for (int j = 0; j < p[0].length; j++) {
				m.set(p[i][j].getMu(), i, j);
			}
		}

		return m;
	}

	public GaussianDistribution predictorProbability(Vector x, Vector y) {
		return new GaussianDistribution(predict(x, y), 1.);
	}

	public double predict(Vector x, Vector y) {
		// double m = x.timesCopy(_UMean).timesCopy(_VMean).timesCopy(y.transpose()).get(0, 0);
		// if (m > 5)
		// m = 5;
		// else if (m < 1)
		// m = 1;
		// return m;
		return 0;
	}

	private GaussianDistribution[][] initLatents(int n, int m) {
		GaussianDistribution[][] p = new GaussianDistribution[n][m];
		Random r = new Random();
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < m; j++) {
				p[i][j] = new GaussianDistribution(r.nextDouble(), 10.);
			}
		}
		return p;
	}

	public static String trainEval(FeaturesSet X, FeaturesSet Y, FeaturesSet R, FeaturesSet X_eval, FeaturesSet Y_eval,
			FeaturesSet R_eval, int k) {

		JointBayesian sb = new JointBayesian();
		sb.train(X, Y, R, k);

		double mae = 0;
		double n = 0;
		for (int i = 0; i < X_eval.size(); i++) {
			for (int j = 0; j < Y_eval.size(); j++) {
				if (R_eval.get(i).get(j) <= 0)
					continue;
				double d = sb.predict((Vector) X_eval.get(i), (Vector) Y_eval.get(j));
				double err = Math.abs(d - R_eval.get(i).get(j));
				mae += err;
				n++;
			}
		}

		return "MAE: " + mae / n;
	}
}
